package com.xx.doublexchat.common.chat.service.strategy.msg;

import cn.hutool.core.bean.BeanUtil;
import com.xx.doublexchat.common.chat.dao.GroupMemberDao;
import com.xx.doublexchat.common.chat.dao.MessageDao;
import com.xx.doublexchat.common.chat.dao.RoomFriendDao;
import com.xx.doublexchat.common.chat.domain.entity.*;
import com.xx.doublexchat.common.chat.domain.enums.MessageTypeEnum;
import com.xx.doublexchat.common.chat.domain.enums.NormalOrNoEnum;
import com.xx.doublexchat.common.chat.domain.vo.request.ChatMessageRequest;
import com.xx.doublexchat.common.chat.service.adapter.MessageAdapter;
import com.xx.doublexchat.common.chat.service.cache.RoomCache;
import com.xx.doublexchat.common.chat.service.cache.RoomGroupCache;
import com.xx.doublexchat.common.common.utils.AssertUtils;
import org.apache.commons.validator.Msg;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.PostConstruct;
import java.lang.reflect.ParameterizedType;

/**
 * 消息发送策略抽象类
 *
 * @param <Req>
 */
public abstract class AbstractMsgHandler<Req> {

    @Autowired
    private MessageDao messageDao;

    private Class<Req> bodyClass;

    @Autowired
    private RoomCache roomCache;

    @Autowired
    private RoomFriendDao roomFriendDao;

    @Autowired
    private RoomGroupCache roomGroupCache;

    @Autowired
    private GroupMemberDao groupMemberDao;

    @PostConstruct
    private void init() {
        //获取泛型的具体类型
        ParameterizedType genericSuperclass = (ParameterizedType) this.getClass().getGenericSuperclass();
        this.bodyClass = (Class<Req>) genericSuperclass.getActualTypeArguments()[0];
        //将策略类注册进工厂
        MsgHandlerFactory.register(getMsgTypeEnum().getType(), this);
    }

    /**
     * 消息类型
     */
    protected abstract MessageTypeEnum getMsgTypeEnum();

    /**
     * 子类拓展保存消息
     *
     * @param message
     * @param body
     */
    protected abstract void saveMsg(Message message, Req body);

    /**
     * 子类拓展消息校验类
     * @param body
     * @param roomId
     * @param uid
     */
    protected void checkMsg(Req body, Long roomId, Long uid) {

    }

    /**
     * 校验并保存方法
     * @param request
     * @param uid
     * @return
     */
    public Long checkAndSaveMsg(ChatMessageRequest request, Long uid) {
        //统一校验
        check(request, uid);
        //反射获取类
        Req body = this.toBean(request.getBody());
        //统一参数校验
        AssertUtils.allCheckValidateThrow(body);
        //子类扩展校验
        checkMsg(body, request.getRoomId(), uid);

        Message insert = MessageAdapter.buildMsgSave(request, uid);
        //统一保存
        messageDao.save(insert);
        //子类扩展保存
        saveMsg(insert, body);
        return insert.getId();
    }

    /**
     * 通用校验
     * @param request
     * @param uid
     */
    private void check(ChatMessageRequest request, Long uid) {
        Room room = roomCache.get(request.getRoomId());
        if (room.isHotRoom()) {//全员群跳过校验
            return;
        }
        if (room.isRoomFriend()) {
            RoomFriend roomFriend = roomFriendDao.getByRoomId(request.getRoomId());
            AssertUtils.equal(NormalOrNoEnum.NORMAL.getStatus(), roomFriend.getStatus(), "您已经被对方拉黑");
            AssertUtils.isTrue(uid.equals(roomFriend.getUid1()) || uid.equals(roomFriend.getUid2()), "您已经被对方拉黑");
        }
        if (room.isRoomGroup()) {
            RoomGroup roomGroup = roomGroupCache.get(request.getRoomId());
            GroupMember member = groupMemberDao.getMember(roomGroup.getId(), uid);
            AssertUtils.isNotEmpty(member, "您已经被移除该群");
        }
    }

    /**
     * 类型转化
     * @param body
     * @return
     */
    private Req toBean(Object body) {
        if (bodyClass.isAssignableFrom(body.getClass())) {
            return (Req) body;
        }
        return BeanUtil.toBean(body, bodyClass);
    }

    /**
     * 展示消息
     * @param message
     * @return
     */
    public abstract Object showMsg(Message message);

    /**
     * 被回复时——展示的消息
     */
    public abstract Object showReplyMsg(Message msg);

    /**
     * 会话列表——展示的消息
     */
    public abstract String showContactMsg(Message msg);
}
